#include <stdio.h>
#include <stdlib.h> 
#include <time.h>

#define MAXDEPTH 3

#define C1 0
#define C2 1
#define C3 2
#define C4 3
#define C5 4
#define C6 5
#define C7 6
#define C8 7
#define E9 8
#define E10 9
#define E11 10
#define E12 11
#define E13 12
#define E14 13
#define E15 14
#define E16 15
#define E17 16
#define E18 17
#define E19 18
#define E20 19


#define PASSEDGES theCube[E9].w, theCube[E9].o, theCube[E10].w, theCube[E10].b, theCube[E11].r, theCube[E11].w, theCube[E12].w, theCube[E12].g, theCube[E13].b, theCube[E13].y, theCube[E14].y, theCube[E14].o, theCube[E15].y, theCube[E15].g, theCube[E16].r, theCube[E16].y, theCube[E17].r, theCube[E17].g, theCube[E18].r, theCube[E18].b, theCube[E19].b, theCube[E19].o, theCube[E20].o, theCube[E20].g

#define PASSCORNERS theCube[C1].w, theCube[C1].o, theCube[C1].g, theCube[C2].w, theCube[C2].b, theCube[C2].o, theCube[C3].r, theCube[C3].w, theCube[C3].g, theCube[C4].r, theCube[C4].w, theCube[C4].b, theCube[C5].r, theCube[C5].b, theCube[C5].y, theCube[C6].b, theCube[C6].o, theCube[C6].y, theCube[C7].r, theCube[C7].y, theCube[C7].g, theCube[C8].o, theCube[C8].y, theCube[C8].g



/*******************************************************************/
/************************** Declarations ***************************/
/*******************************************************************/

struct aCube {
  short pos;
  short r;
  short w;
  short b;
  short o;
  short y;
  short g;
};

void allRotations();
char getColor(short s);
void resetCube( struct aCube *);
void scramble( struct aCube *, short);
void printStepCube( struct aCube *);
void printCrossCube( struct aCube *);
void saveCornerCubie( struct aCube *, FILE*, short);
void saveEdgeCubie( struct aCube *, FILE*, short);
void generateTables( FILE*, FILE*, struct aCube *, short );

void generateEdges( struct aCube *, FILE*, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short);

void generateCorners( struct aCube *, FILE*, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short );

void setEdges( struct aCube *, short , short, short , short, short , short, short , short, short , short, short , short, short , short, short , short, short , short, short , short, short , short, short , short);

void setCorners( struct aCube *, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short, short);


/*Moves denoted in number of clockwise rotations*/

int rotate( struct aCube *, char, int);

void r1c( struct aCube *);
void r1e( struct aCube *);
void r2c( struct aCube *);
void r2e( struct aCube *);
void r3c( struct aCube *);
void r3e( struct aCube *);

void w1c( struct aCube *);
void w1e( struct aCube *);
void w2c( struct aCube *);
void w2e( struct aCube *);
void w3c( struct aCube *);
void w3e( struct aCube *);

void b1c( struct aCube *);
void b1e( struct aCube *);
void b2c( struct aCube *);
void b2e( struct aCube *);
void b3c( struct aCube *);
void b3e( struct aCube *);

void o1c( struct aCube *);
void o1e( struct aCube *);
void o2c( struct aCube *);
void o2e( struct aCube *);
void o3c( struct aCube *);
void o3e( struct aCube *);

void y1c( struct aCube *);
void y1e( struct aCube *);
void y2c( struct aCube *);
void y2e( struct aCube *);
void y3c( struct aCube *);
void y3e( struct aCube *);

void g1c( struct aCube *);
void g1e( struct aCube *);
void g2c( struct aCube *);
void g2e( struct aCube *);
void g3c( struct aCube *);
void g3e( struct aCube *);


/******************************************************************/
/************************ Main Function ***************************/
/******************************************************************/

int main() {
  struct aCube theCube[20] = {
    { 0, 0, 2, 0, 4, 0, 6},
    { 1, 0, 2, 3, 4, 0, 0},
    { 2, 1, 2, 0, 0, 0, 6},
    { 3, 1, 2, 3, 0, 0, 0},
    { 4, 1, 0, 3, 0, 5, 0},
    { 5, 0, 0, 3, 4, 5, 0},
    { 6, 1, 0, 0, 0, 5, 6},
    { 7, 0, 0, 0, 4, 5, 6},
    { 8, 0, 2, 0, 4, 0, 0},
    { 9, 0, 2, 3, 0, 0, 0},
    {10, 1, 2, 0, 0, 0, 0},
    {11, 0, 2, 0, 0, 0, 6},
    {12, 0, 0, 3, 0, 5, 0},
    {13, 0, 0, 0, 4, 5, 0},
    {14, 0, 0, 0, 0, 5, 6},
    {15, 1, 0, 0, 0, 5, 0},
    {16, 1, 0, 0, 0, 0, 6},
    {17, 1, 0, 3, 0, 0, 0},
    {18, 0, 0, 3, 4, 0, 0},
    {19, 0, 0, 0, 4, 0, 6}
  };
 
  FILE* cornerFile;
  FILE* edgeFile;

  cornerFile = fopen("cornerTable.txt", "w");
  edgeFile = fopen("edgeTable.txt", "w");
  generateCorners( theCube, cornerFile, 0, PASSCORNERS );
  generateEdges(   theCube, edgeFile, 0, PASSEDGES );

  fclose(cornerFile);
  fclose(edgeFile);

  return 0;
}

/*******************************************************************/
/********************** Function Definitions ***********************/
/*******************************************************************/

void generateTables( FILE* cornerFile, FILE* edgeFile, struct aCube * cube, short currentDepth) {
    
  if( MAXDEPTH == currentDepth ) return;
  else{
    char face[6] = { 'r', 'w', 'b', 'o', 'y', 'g' };
    int i, j;
    for( i=0; i<=5; i++) {
      for( j=1; j<=3; j++) {
	rotate( cube, face[i], j);
	saveCornerCubie( cube, cornerFile, currentDepth+1);
	saveEdgeCubie(   cube, edgeFile,   currentDepth+1);
	generateTables( cornerFile, edgeFile, cube, currentDepth+1);
      }
    }
  }
}


void generateCorners( struct aCube * theCube, FILE* cornerFile, short currentDepth, short input01, short input02, short input03, short input04, short input05, short input06, short input07, short input08, short input09, short input10, short input11, short input12, short input13, short input14, short input15, short input16, short input17, short input18, short input19, short input20, short input21, short input22, short input23, short input24 ) {
  theCube[C1].w = input01;
  theCube[C1].o = input02;
  theCube[C1].g = input03;
  theCube[C2].w = input04;
  theCube[C2].b = input05;
  theCube[C2].o = input06;
  theCube[C3].r = input07;
  theCube[C3].w = input08;
  theCube[C3].g = input09;
  theCube[C4].r = input10;
  theCube[C4].w = input11;
  theCube[C4].b = input12;
  theCube[C5].r = input13;
  theCube[C5].b = input14;
  theCube[C5].y = input15;
  theCube[C6].b = input16;
  theCube[C6].o = input17;
  theCube[C6].y = input18;
  theCube[C7].r = input19;
  theCube[C7].y = input20;
  theCube[C7].g = input21;
  theCube[C8].o = input22;
  theCube[C8].y = input23;
  theCube[C8].g = input24;

  if( MAXDEPTH == currentDepth ) return;
  else{
    char face[6] = { 'r', 'w', 'b', 'o', 'y', 'g' };
    int i, j;
    for( i=0; i<=5; i++) {
      for( j=1; j<=3; j++) {
        rotate( theCube, face[i], j);
        saveCornerCubie( theCube, cornerFile, currentDepth+1);
        generateCorners( theCube, cornerFile, currentDepth+1, PASSCORNERS);
      }
    }
  }
}

void generateEdges( struct aCube * theCube, FILE* edgeFile, short currentDepth, short input01, short input02, short input03, short input04, short input05, short input06, short input07, short input08, short input09, short input10, short input11, short input12, short input13, short input14, short input15, short input16, short input17, short input18, short input19, short input20, short input21, short input22, short input23, short input24 ) {

  theCube[ E9].w = input01;
  theCube[ E9].o = input02;
  theCube[E10].w = input03;
  theCube[E10].b = input04;
  theCube[E11].r = input05;
  theCube[E11].w = input06;
  theCube[E12].w = input07;
  theCube[E12].g = input08;
  theCube[E13].b = input09;
  theCube[E13].y = input10;
  theCube[E14].y = input11;
  theCube[E14].o = input12;
  theCube[E15].y = input13;
  theCube[E15].g = input14;
  theCube[E16].r = input15;
  theCube[E16].y = input16;
  theCube[E17].r = input17;
  theCube[E17].g = input18;
  theCube[E18].r = input19;
  theCube[E18].b = input20;
  theCube[E19].b = input21;
  theCube[E19].o = input22;
  theCube[E20].o = input23;
  theCube[E20].g = input24;

  if( MAXDEPTH == currentDepth ) return;
  else{
    char face[6] = { 'r', 'w', 'b', 'o', 'y', 'g' };
    int i, j;
    for( i=0; i<=5; i++) {
      for( j=1; j<=3; j++) {
        rotate( theCube, face[i], j);
        saveEdgeCubie( theCube, edgeFile, currentDepth+1);
        generateEdges( theCube, edgeFile, currentDepth+1, PASSEDGES);
      }
    }
  }  
}


void setCorners( struct aCube * cube, short input01, short input02, short input03, short input04, short input05, short input06, short input07, short input08, short input09, short input10, short input11, short input12, short input13, short input14, short input15, short input16, short input17, short input18, short input19, short input20, short input21, short input22, short input23, short input24 ) {
  cube[C1].w = input01;
  cube[C1].o = input02;
  cube[C1].g = input03;
  cube[C2].w = input04;
  cube[C2].b = input05;
  cube[C2].o = input06;
  cube[C3].r = input07;
  cube[C3].w = input08;
  cube[C3].g = input09;
  cube[C4].r = input10;
  cube[C4].w = input11;
  cube[C4].b = input12;
  cube[C5].r = input13;
  cube[C5].b = input14;
  cube[C5].y = input15;
  cube[C6].b = input16;
  cube[C6].o = input17;
  cube[C6].y = input18;
  cube[C7].r = input19;
  cube[C7].y = input20;
  cube[C7].g = input21;
  cube[C8].o = input22;
  cube[C8].y = input23;
  cube[C8].g = input24;
}




void setEdges( struct aCube * cube, short input01, short input02, short input03, short input04, short input05, short input06, short input07, short input08, short input09, short input10, short input11, short input12, short input13, short input14, short input15, short input16, short input17, short input18, short input19, short input20, short input21, short input22, short input23, short input24 ) {
  
  cube[ E9].w = input01;
  cube[ E9].o = input02;
  cube[E10].w = input03;
  cube[E10].b = input04;
  cube[E11].r = input05;
  cube[E11].w = input06;
  cube[E12].w = input07;
  cube[E12].g = input08;
  cube[E13].b = input09;
  cube[E13].y = input10;
  cube[E14].y = input11;
  cube[E14].o = input12;
  cube[E15].y = input13;
  cube[E15].g = input14;
  cube[E16].r = input15;
  cube[E16].y = input16;
  cube[E17].r = input17;
  cube[E17].g = input18;
  cube[E18].r = input19;
  cube[E18].b = input20;
  cube[E19].b = input21;
  cube[E19].o = input22;
  cube[E20].o = input23;
  cube[E20].g = input24;
}


void scramble( struct aCube * cube, short n ) {
  srand( (unsigned int)time( NULL ) );
  
  short iter = 0;
  for(iter = 0; iter<n; iter++) {
    short randFace = rand() % 6;
    short randTurn = rand() % 3;
    char face[6] = { 'r', 'w', 'b', 'o', 'y', 'g' };
    int turn[3] = { 1, 2, 3 };
    rotate(cube, face[ randFace ], turn[ randTurn ]);
    printf("\n\nface:%2c rotate:%2d\n\n", face[ randFace ], turn[ randTurn ]); 
  }
}


void resetCube( struct aCube * cube) {
  struct aCube goalState[20] = {
    { 0, 0, 2, 0, 4, 0, 6},
    { 1, 0, 2, 3, 4, 0, 0},
    { 2, 1, 2, 0, 0, 0, 6},
    { 3, 1, 2, 3, 0, 0, 0},
    { 4, 1, 0, 3, 0, 5, 0},
    { 5, 0, 0, 3, 4, 5, 0},
    { 6, 1, 0, 0, 0, 5, 6},
    { 7, 0, 0, 0, 4, 5, 6},
    { 8, 0, 2, 0, 4, 0, 0},
    { 9, 0, 2, 3, 0, 0, 0},
    {10, 1, 2, 0, 0, 0, 0},
    {11, 0, 2, 0, 0, 0, 6},
    {12, 0, 0, 3, 0, 5, 0},
    {13, 0, 0, 0, 4, 5, 0},
    {14, 0, 0, 0, 0, 5, 6},
    {15, 1, 0, 0, 0, 5, 0},
    {16, 1, 0, 0, 0, 0, 6},
    {17, 1, 0, 3, 0, 0, 0},
    {18, 0, 0, 3, 4, 0, 0},
    {19, 0, 0, 0, 4, 0, 6}
  };
  int j;		
  	for( j=1; j<=7; j++) {
          cube[j] = goalState[j];
          }
}

void allRotations() {
  int x,i,j;
  char face[6] = { 'r', 'w', 'b', 'o', 'y', 'g' };
  for( i=0; i<=5; i++) {
      for( j=1; j<=3; j++) {
	  struct aCube cube[20] = {
	    { 0, 0, 2, 0, 4, 0, 6},
	    { 1, 0, 2, 3, 4, 0, 0},
	    { 2, 1, 2, 0, 0, 0, 6},
	    { 3, 1, 2, 3, 0, 0, 0},
	    { 4, 1, 0, 3, 0, 5, 0},
	    { 5, 0, 0, 3, 4, 5, 0},
	    { 6, 1, 0, 0, 0, 5, 6},
	    { 7, 0, 0, 0, 4, 5, 6},
	    { 8, 0, 2, 0, 4, 0, 0},
	    { 9, 0, 2, 3, 0, 0, 0},
	    {10, 1, 2, 0, 0, 0, 0},
	    {11, 0, 2, 0, 0, 0, 6},
	    {12, 0, 0, 3, 0, 5, 0},
	    {13, 0, 0, 0, 4, 5, 0},
	    {14, 0, 0, 0, 0, 5, 6},
	    {15, 1, 0, 0, 0, 5, 0},
	    {16, 1, 0, 0, 0, 0, 6},
	    {17, 1, 0, 3, 0, 0, 0},
	    {18, 0, 0, 3, 4, 0, 0},
	    {19, 0, 0, 0, 4, 0, 6}
	  };
          printf("\n\nface:%2c rotate:%2d\n\n", face[i], j);
          x = rotate( cube, face[i], j);
          printCrossCube( cube);
          }
  }
}


/*******************************************************************/
/***************** Print / Save State Funcitions *******************/
/*******************************************************************/

void saveCornerCubie( struct aCube * cube, FILE* filename, short distToGoal) {
  fprintf( filename, "%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i\n", cube[C1].w, cube[C1].o, cube[C1].g, cube[C2].w, cube[C2].b, cube[C2].o, cube[C3].r, cube[C3].w, cube[C3].g, cube[C4].r, cube[C4].w, cube[C4].b, cube[C5].r, cube[C5].b, cube[C5].y, cube[C6].b, cube[C6].o, cube[C6].y, cube[C7].r, cube[C7].y, cube[C7].g, cube[C8].o, cube[C8].y, cube[C8].g, distToGoal);
}

void saveEdgeCubie( struct aCube * cube, FILE* filename, short distToGoal) {
  fprintf( filename, "%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i\n", cube[E9].w, cube[E9].o, cube[E10].w, cube[E10].b, cube[E11].r, cube[E11].w, cube[E12].w, cube[E12].g, cube[E13].b, cube[E13].y, cube[E14].y, cube[E14].o, cube[E15].y, cube[E15].g, cube[E16].r, cube[E16].y, cube[E17].r, cube[E17].g, cube[E18].r, cube[E18].b, cube[E19].b, cube[E19].o, cube[E20].o, cube[E20].g, distToGoal);
}

void printStepCube(struct aCube * cube) {
  printf("\n");
  printf("%c  %c  %c\n", 
	 getColor( cube[C1].w ), getColor( cube[E9].w ),  getColor( cube[C2].w) );
  printf("%c  W  %c \n", 
	 getColor( cube[E12].w),              getColor( cube[E10].w) );
  printf("%c  %c  %c \n\n", 
	 getColor( cube[C3].w), getColor( cube[E11].w ), getColor( cube[C4].w) );

  printf("%c  %c  %c    %c  %c  %c\n", 
	 getColor( cube[C3].r ), getColor( cube[E11].r ), getColor( cube[C4].r ),  
	 getColor( cube[C4].b ), getColor( cube[E10].b ), getColor( cube[C2].b) );
  printf("%c  R  %c    %c  B  %c\n", 
	 getColor( cube[E17].r ),  getColor( cube[E18].r ), 
	 getColor( cube[E18].b ),  getColor( cube[E19].b ) );
  printf("%c  %c  %c    %c  %c  %c\n\n", 
	 getColor( cube[C7].r ),  getColor( cube[E16].r ), getColor( cube[C5].r ), 
	 getColor( cube[C5].b ), getColor( cube[E13].b ), getColor( cube[C6].b) ) ;

  printf("\t   %c  %c  %c    %c  %c  %c\n",  
	 getColor( cube[C5].y ), getColor( cube[E13].y ), getColor( cube[C6].y) ,  
	 getColor( cube[C6].o), getColor( cube[E19].o ), getColor( cube[C2].o) );
  printf("\t   %c  Y  %c    %c  O  %c\n", 
	 getColor( cube[E16].y ), getColor( cube[E14].y ), 
	 getColor( cube[E14].o ), getColor( cube[E9].o) );
  printf("\t   %c  %c  %c    %c  %c  %c\n\n", 
	 getColor( cube[C7].y ), getColor( cube[E15].y ), getColor( cube[C8].y ), 
	 getColor( cube[C8].o ), getColor( cube[E20].o ), getColor( cube[C1].o));

  printf("\t\t      %c  %c  %c\n",  
	 getColor( cube[C8].g ), getColor( cube[E20].g), getColor( cube[C1].g) );
  printf("\t\t      %c  G  %c\n", 
	 getColor( cube[E15].g ),  getColor( cube[E12].g) );
  printf("\t\t      %c  %c  %c\n",  
	 getColor( cube[C7].g ), getColor( cube[E17].g ), getColor( cube[C3].g) );
  printf("\n");
}


void printCrossCube(struct aCube * cube) {
  printf("\n");
  printf("\t   %c  %c  %c\t       %c  %c  %c\n",
         getColor( cube[C8].o), getColor( cube[E14].o), getColor( cube[C6].o),
         getColor( cube[C2].o), getColor( cube[E9].o),  getColor( cube[C1].o)  );
  printf("\t   %c  O  %c\t       %c  O  %c\n",
         getColor( cube[E20].o), getColor( cube[E19].o),
         getColor( cube[E19].o), getColor( cube[E20].o)  );
  printf("\t   %c  %c  %c\t       %c  %c  %c\n",
         getColor( cube[C1].o), getColor( cube[E9].o),  getColor( cube[C2].o),
         getColor( cube[C6].o), getColor( cube[E14].o), getColor( cube[C8].o)  );
  printf("\n");
  printf(" %c  %c  %c   %c  %c  %c   %c  %c  %c   %c  %c  %c   %c  %c  %c\n",
         getColor( cube[C8].g), getColor( cube[E20].g), getColor( cube[C1].g),
         getColor( cube[C1].w), getColor( cube[E9].w),  getColor( cube[C2].w),
         getColor( cube[C2].b), getColor( cube[E19].b), getColor( cube[C6].b),
         getColor( cube[C6].y), getColor( cube[E14].y), getColor( cube[C8].y),
         getColor( cube[C8].g), getColor( cube[E20].g), getColor( cube[C1].g)  );
  printf(" %c  G  %c   %c  W  %c   %c  B  %c   %c  Y  %c   %c  G  %c\n",
         getColor( cube[E15].g), getColor( cube[E12].g),
         getColor( cube[E12].w), getColor( cube[E10].w),
         getColor( cube[E10].b), getColor( cube[E13].b),
         getColor( cube[E13].y), getColor( cube[E15].y),
         getColor( cube[E15].g), getColor( cube[E12].g)  );
  printf(" %c  %c  %c   %c  %c  %c   %c  %c  %c   %c  %c  %c   %c  %c  %c\n",
         getColor( cube[C7].g), getColor( cube[E17].g), getColor( cube[C3].g),
         getColor( cube[C3].w), getColor( cube[E11].w), getColor( cube[C4].w),
         getColor( cube[C4].b), getColor( cube[E18].b), getColor( cube[C5].b),
         getColor( cube[C5].y), getColor( cube[E16].y), getColor( cube[C7].y),
         getColor( cube[C7].g), getColor( cube[E17].g), getColor( cube[C3].g)  );
  printf("\n");
  printf("\t   %c  %c  %c\t       %c  %c  %c\n",
         getColor( cube[C3].r), getColor( cube[E11].r), getColor( cube[C4].r),
         getColor( cube[C5].r), getColor( cube[E16].r), getColor( cube[C7].r)  );
  printf("\t   %c  R  %c\t       %c  R  %c\n",
         getColor( cube[E17].r), getColor( cube[E18].r),
         getColor( cube[E18].r), getColor( cube[E17].r)  );
  printf("\t   %c  %c  %c\t       %c  %c  %c\n",
         getColor( cube[C7].r), getColor( cube[E16].r), getColor( cube[C5].r),
         getColor( cube[C4].r), getColor( cube[E11].r), getColor( cube[C3].r)  );
  printf("\n");
}

char getColor(short s) {
  if      ( s == 1 ) return 'R';
  else if ( s == 2 ) return 'W';
  else if ( s == 3 ) return 'B';
  else if ( s == 4 ) return 'O';
  else if ( s == 5 ) return 'Y';
  else if ( s == 6 ) return 'G';
  else return '!';
}


/*******************************************************************/
/********************* Face Rotation Funcitions ********************/
/*******************************************************************/

void r1c(struct aCube * cube) {
  short temp = cube[C3].r;
  cube[C3].r = cube[C7].r;
  cube[C7].r = cube[C5].r;
  cube[C5].r = cube[C4].r;
  cube[C4].r = temp;

  temp = cube[C3].w;
  cube[C3].w = cube[C7].g;
  cube[C7].g = cube[C5].y;
  cube[C5].y = cube[C4].b;
  cube[C4].b = temp;

  temp = cube[C3].g;
  cube[C3].g = cube[C7].y;
  cube[C7].y = cube[C5].b;
  cube[C5].b = cube[C4].w;
  cube[C4].w = temp;
  
}

void r1e(struct aCube * cube) {
  short temp = cube[E11].r;
  cube[E11].r = cube[E17].r;
  cube[E17].r = cube[E16].r;
  cube[E16].r = cube[E18].r;
  cube[E18].r = temp;

  temp = cube[E11].w;
  cube[E11].w = cube[E17].g;
  cube[E17].g = cube[E16].y;
  cube[E16].y = cube[E18].b;
  cube[E18].b = temp;
}

void r2c(struct aCube * cube) {
  short temp = cube[C3].r;
  cube[C3].r = cube[C5].r;
  cube[C5].r = temp;

  temp = cube[C4].r;
  cube[C4].r = cube[C7].r;
  cube[C7].r = temp;

  temp = cube[C3].w;
  cube[C3].w = cube[C5].y;
  cube[C5].y = temp;

  temp = cube[C3].g;
  cube[C3].g = cube[C5].b; 
  cube[C5].b = temp;

  temp = cube[C4].w;
  cube[C4].w = cube[C7].y;
  cube[C7].y = temp;

  temp = cube[C4].b;
  cube[C4].b = cube[C7].g;
  cube[C7].g = temp;
}

void r2e(struct aCube * cube) {
  short temp = cube[E11].r;
  cube[E11].r = cube[E16].r;
  cube[E16].r = temp;

  temp = cube[E17].r;
  cube[E17].r = cube[E18].r;
  cube[E18].r = temp;

  temp = cube[E11].w;
  cube[E11].w = cube[E16].y;
  cube[E16].y = temp;

  temp = cube[E17].g;
  cube[E17].g = cube[E18].b;
  cube[E18].b = temp;
}

void r3c(struct aCube * cube) {
  short temp = cube[C3].r;
  cube[C3].r = cube[C4].r;
  cube[C4].r = cube[C5].r;
  cube[C5].r = cube[C7].r;
  cube[C7].r = temp;

  temp = cube[C3].w;
  cube[C3].w = cube[C4].b;
  cube[C4].b = cube[C5].y;
  cube[C5].y = cube[C7].g;
  cube[C7].g = temp;

  temp = cube[C3].g;
  cube[C3].g = cube[C4].w;
  cube[C4].w = cube[C5].b;
  cube[C5].b = cube[C7].y;
  cube[C7].y = temp;
}

void r3e(struct aCube * cube) {
  short temp = cube[E11].r;
  cube[E11].r = cube[E18].r;
  cube[E18].r = cube[E16].r;
  cube[E16].r = cube[E17].r;
  cube[E17].r = temp;

  temp = cube[E11].w;
  cube[E11].w = cube[E18].b;
  cube[E18].b = cube[E16].y;
  cube[E16].y = cube[E17].g;
  cube[E17].g = temp;
}



void w1c(struct aCube * cube) {
  short temp = cube[C1].o;
  cube[C1].o = cube[C3].g;
  cube[C3].g = cube[C4].r;
  cube[C4].r = cube[C2].b;
  cube[C2].b = temp;

  temp = cube[C1].g;
  cube[C1].g = cube[C3].r;
  cube[C3].r = cube[C4].b;
  cube[C4].b = cube[C2].o;
  cube[C2].o = temp;

  temp = cube[C1].w;
  cube[C1].w = cube[C3].w;
  cube[C3].w = cube[C4].w;
  cube[C4].w = cube[C2].w;
  cube[C2].w = temp;
}

void w1e(struct aCube * cube) {
  short temp = cube[E9].o;
  cube[E9].o = cube[E12].g;
  cube[E12].g = cube[E11].r;
  cube[E11].r = cube[E10].b;
  cube[E10].b = temp;

  temp = cube[E9].w;
  cube[E9].w = cube[E12].w;
  cube[E12].w = cube[E11].w;
  cube[E11].w = cube[E10].w;
  cube[E10].w = temp;
}

void w2c(struct aCube * cube) {
  short temp = cube[C1].o;
  cube[C1].o = cube[C4].r;
  cube[C4].r = temp;
  temp = cube[C1].g;
  cube[C1].g = cube[C4].b;
  cube[C4].b = temp;

  temp = cube[C2].b;
  cube[C2].b = cube[C3].g;
  cube[C3].g = temp;
  temp = cube[C2].o;
  cube[C2].o = cube[C3].r;
  cube[C3].r = temp;

  temp = cube[C1].w;
  cube[C1].w = cube[C4].w;
  cube[C4].w = temp;
  temp = cube[C2].w;
  cube[C2].w = cube[C3].w;
  cube[C3].w = temp;
}

void w2e(struct aCube * cube) {
  short temp = cube[E9].o;
  cube[E9].o = cube[E11].r;
  cube[E11].r = temp;
  temp = cube[E12].g; 
  cube[E12].g = cube[E10].b;
  cube[E10].b = temp;
  
  temp = cube[E9].w;
  cube[E9].w = cube[E11].w;
  cube[E11].w = temp;
  temp = cube[E12].w;
  cube[E12].w = cube[E10].w;
  cube[E10].w = temp;
}

void w3c(struct aCube * cube) {
  short temp = cube[C1].o;
  cube[C1].o = cube[C2].b;
  cube[C2].b = cube[C4].r;
  cube[C4].r = cube[C3].g;
  cube[C3].g = temp; 

  temp = cube[C1].g;
  cube[C1].g = cube[C2].o;
  cube[C2].o = cube[C4].b;
  cube[C4].b = cube[C3].r;
  cube[C3].r = temp;

  temp = cube[C1].w;
  cube[C1].w = cube[C2].w;
  cube[C2].w = cube[C4].w;
  cube[C4].w = cube[C3].w;
  cube[C3].w = temp;
}

void w3e(struct aCube * cube) {
  short temp  = cube[E9].o;
  cube[E9].o  = cube[E10].b;
  cube[E10].b = cube[E11].r;
  cube[E11].r = cube[E12].g;
  cube[E12].g = temp;

  temp = cube[E9].w;
  cube[E9].w  = cube[E10].w;
  cube[E10].w = cube[E11].w;
  cube[E11].w = cube[E12].w;
  cube[E12].w = temp;
}


void b1c(struct aCube * cube) {
  short temp = cube[C4].b;
  cube[C4].b = cube[C5].b;
  cube[C5].b = cube[C6].b;
  cube[C6].b = cube[C2].b;
  cube[C2].b = temp;

  temp = cube[C4].w;
  cube[C4].w = cube[C5].r;
  cube[C5].r = cube[C6].y;
  cube[C6].y = cube[C2].o;
  cube[C2].o = temp;

  temp = cube[C4].r;
  cube[C4].r = cube[C5].y;
  cube[C5].y = cube[C6].o;
  cube[C6].o = cube[C2].w;
  cube[C2].w = temp;
}

void b1e(struct aCube * cube) {
  short temp = cube[E10].b;
  cube[E10].b = cube[E18].b;
  cube[E18].b = cube[E13].b;
  cube[E13].b = cube[E19].b;
  cube[E19].b = temp;
  
  temp = cube[E10].w;
  cube[E10].w = cube[E18].r;
  cube[E18].r = cube[E13].y;
  cube[E13].y = cube[E19].o;
  cube[E19].o = temp;
}

void b2c(struct aCube * cube) {
  short temp = cube[C4].b;
  cube[C4].b = cube[C6].b;
  cube[C6].b = temp;
  temp = cube[C2].b;
  cube[C2].b = cube[C5].b;
  cube[C5].b = temp;

  temp = cube[C4].w;
  cube[C4].w = cube[C6].y;
  cube[C6].y = temp;
  temp = cube[C4].r;
  cube[C4].r = cube[C6].o;
  cube[C6].o = temp;

  temp = cube[C2].w;
  cube[C2].w = cube[C5].y;
  cube[C5].y = temp;
  temp = cube[C2].o;
  cube[C2].o = cube[C5].r;
  cube[C5].r = temp;
}

void b2e(struct aCube * cube) {
  short temp = cube[E10].b;
  cube[E10].b = cube[E13].b;
  cube[E13].b = temp;
  temp = cube[E18].b;
  cube[E18].b = cube[E19].b;
  cube[E19].b = temp;

  temp = cube[E10].w;
  cube[E10].w = cube[E13].y;
  cube[E13].y = temp;
  temp = cube[E18].r;
  cube[E18].r = cube[E19].o;
  cube[E19].o = temp;
}

void b3c(struct aCube * cube) {
  short temp = cube[C4].b;
  cube[C4].b = cube[C2].b;
  cube[C2].b = cube[C6].b;
  cube[C6].b = cube[C5].b;
  cube[C5].b = temp;

  temp = cube[C4].w;
  cube[C4].w = cube[C2].o;
  cube[C2].o = cube[C6].y;
  cube[C6].y = cube[C5].r;
  cube[C5].r = temp;

  temp = cube[C4].r;
  cube[C4].r = cube[C2].w;
  cube[C2].w = cube[C6].o;
  cube[C6].o = cube[C5].y;
  cube[C5].y = temp;
}

void b3e(struct aCube * cube) {
  short temp = cube[E10].b;
  cube[E10].b = cube[E19].b;
  cube[E19].b = cube[E13].b;
  cube[E13].b = cube[E18].b;
  cube[E18].b = temp;

  temp = cube[E10].w;
  cube[E10].w = cube[E19].o;
  cube[E19].o = cube[E13].y;
  cube[E13].y = cube[E18].r;
  cube[E18].r = temp;
}



void o1c(struct aCube * cube) {
  short temp = cube[C6].o;
  cube[C6].o = cube[C8].o;
  cube[C8].o = cube[C1].o;
  cube[C1].o = cube[C2].o;
  cube[C2].o = temp;

  temp = cube[C6].b;
  cube[C6].b = cube[C8].y;
  cube[C8].y = cube[C1].g;
  cube[C1].g = cube[C2].w;
  cube[C2].w = temp;

  temp = cube[C6].y; 
  cube[C6].y = cube[C8].g;
  cube[C8].g = cube[C1].w;
  cube[C1].w = cube[C2].b;
  cube[C2].b = temp;
}

void o1e(struct aCube * cube) {
  short temp = cube[E19].o;
  cube[E19].o = cube[E14].o;
  cube[E14].o = cube[E20].o;
  cube[E20].o = cube[E9].o;
  cube[E9].o = temp;
  
  temp = cube[E19].b;
  cube[E19].b = cube[E14].y;
  cube[E14].y = cube[E20].g;
  cube[E20].g = cube[E9].w;
  cube[E9].w = temp;
}

void o2c(struct aCube * cube) {
  short temp = cube[C6].o;
  cube[C6].o = cube[C1].o;
  cube[C1].o = temp;

  temp = cube[C2].o;
  cube[C2].o = cube[C8].o;
  cube[C8].o = temp;

  temp = cube[C6].b;
  cube[C6].b = cube[C1].g;
  cube[C1].g = temp;

  temp = cube[C6].y;
  cube[C6].y = cube[C1].w;
  cube[C1].w = temp;

  temp = cube[C2].b;
  cube[C2].b = cube[C8].g;
  cube[C8].g = temp;

  temp = cube[C2].w;
  cube[C2].w = cube[C8].y;
  cube[C8].y = temp;
}

void o2e(struct aCube * cube) {
  short temp = cube[E19].o;
  cube[E19].o = cube[E20].o;
  cube[E20].o = temp;

  temp = cube[E14].o;
  cube[E14].o = cube[E9].o;
  cube[E9].o = temp;

  temp = cube[E19].b;
  cube[E19].b = cube[E20].g;
  cube[E20].g = temp;

  temp = cube[E14].y;
  cube[E14].y = cube[E9].w;
  cube[E9].w = temp;
}

void o3c(struct aCube * cube) {
  short temp = cube[C6].o;
  cube[C6].o = cube[C2].o;
  cube[C2].o = cube[C1].o;
  cube[C1].o = cube[C8].o;
  cube[C8].o = temp;

  temp = cube[C6].b;
  cube[C6].b = cube[C2].w;
  cube[C2].w = cube[C1].g; 
  cube[C1].g = cube[C8].y;
  cube[C8].y = temp;

  temp = cube[C6].y;
  cube[C6].y = cube[C2].b; 
  cube[C2].b = cube[C1].w;
  cube[C1].w = cube[C8].g;
  cube[C8].g = temp;
}

void o3e(struct aCube * cube) {
  short temp = cube[E19].o;
  cube[E19].o = cube[E9].o;
  cube[E9].o  = cube[E20].o;
  cube[E20].o = cube[E14].o;
  cube[E14].o = temp;

  temp = cube[E19].b;
  cube[E19].b = cube[E9].w;
  cube[E9].w  = cube[E20].g;
  cube[E20].g  = cube[E14].y;
  cube[E14].y =temp;
}


void y1c(struct aCube * cube) {
  short temp = cube[C8].y;
  cube[C8].y = cube[C6].y;
  cube[C6].y = cube[C5].y;
  cube[C5].y = cube[C7].y;
  cube[C7].y = temp;

  temp = cube[C8].o;
  cube[C8].o = cube[C6].b;
  cube[C6].b = cube[C5].r;
  cube[C5].r = cube[C7].g;
  cube[C7].g = temp;

  temp = cube[C8].g;
  cube[C8].g = cube[C6].o;
  cube[C6].o = cube[C5].b;
  cube[C5].b = cube[C7].r;
  cube[C7].r = temp;
}

void y1e(struct aCube * cube) {
  short temp = cube[E14].y;
  cube[E14].y = cube[E13].y;
  cube[E13].y = cube[E16].y;
  cube[E16].y = cube[E15].y;
  cube[E15].y = temp;

  temp = cube[E14].o;
  cube[E14].o = cube[E13].b;
  cube[E13].b = cube[E16].r;
  cube[E16].r = cube[E15].g;
  cube[E15].g = temp;
}

void y2c(struct aCube * cube) {
  short temp = cube[C6].y;
  cube[C6].y = cube[C7].y;
  cube[C7].y = temp;
  temp = cube[C5].y;
  cube[C5].y = cube[C8].y;
  cube[C8].y = temp;

  temp = cube[C6].o;
  cube[C6].o = cube[C7].r;
  cube[C7].r = temp;
  temp = cube[C5].b;
  cube[C5].b = cube[C8].g;
  cube[C8].g = temp;

  temp = cube[C6].b;
  cube[C6].b = cube[C7].g;
  cube[C7].g = temp;
  temp = cube[C5].r;
  cube[C5].r = cube[C8].o;
  cube[C8].o = temp;
}

void y2e(struct aCube * cube) {
  short temp = cube[E14].y;
  cube[E14].y = cube[E16].y;
  cube[E16].y = temp;
  temp = cube[E13].y;
  cube[E13].y = cube[E15].y;
  cube[E15].y = temp;

  temp = cube[E14].o;
  cube[E14].o = cube[E16].r;
  cube[E16].r = temp;
  temp = cube[E13].b;
  cube[E13].b = cube[E15].g;
  cube[E15].g = temp;
}

void y3c(struct aCube * cube) {
  short temp = cube[C8].y;
  cube[C8].y = cube[C7].y;
  cube[C7].y = cube[C5].y;
  cube[C5].y = cube[C6].y;
  cube[C6].y = temp;

  temp = cube[C8].o;
  cube[C8].o = cube[C7].g;
  cube[C7].g = cube[C5].r;
  cube[C5].r = cube[C6].b;
  cube[C6].b = temp;

  temp = cube[C8].g;
  cube[C8].g = cube[C7].r;
  cube[C7].r = cube[C5].b;
  cube[C5].b = cube[C6].o;
  cube[C6].o = temp;
}

void y3e(struct aCube * cube) {
  short temp = cube[E14].y;
  cube[E14].y = cube[E15].y;
  cube[E15].y = cube[E16].y;
  cube[E16].y = cube[E13].y;
  cube[E13].y = temp;

  temp = cube[E14].o;
  cube[E14].o = cube[E15].g;
  cube[E15].g = cube[E16].r;
  cube[E16].r = cube[E13].b;
  cube[E13].b = temp;
}



void g1c(struct aCube * cube) {
  short temp = cube[C8].g;
  cube[C8].g = cube[C7].g;
  cube[C7].g = cube[C3].g;
  cube[C3].g = cube[C1].g;
  cube[C1].g = temp;

  temp = cube[C8].y;
  cube[C8].y = cube[C7].r;
  cube[C7].r = cube[C3].w;
  cube[C3].w = cube[C1].o;
  cube[C1].o = temp;

  temp = cube[C8].o;
  cube[C8].o = cube[C7].y;
  cube[C7].y = cube[C3].r;
  cube[C3].r = cube[C1].w;
  cube[C1].w = temp;
}

void g1e(struct aCube * cube) {
  short temp = cube[E20].g;
  cube[E20].g = cube[E15].g;
  cube[E15].g = cube[E17].g;
  cube[E17].g = cube[E12].g;
  cube[E12].g = temp;

  temp = cube[E20].o;
  cube[E20].o = cube[E15].y;
  cube[E15].y = cube[E17].r;
  cube[E17].r = cube[E12].w;
  cube[E12].w = temp;
}

void g2c(struct aCube * cube) {
  short temp = cube[C1].g;
  cube[C1].g = cube[C7].g;
  cube[C7].g = temp;
  temp = cube[C3].g;
  cube[C3].g = cube[C8].g;
  cube[C8].g = temp;

  temp = cube[C1].o;
  cube[C1].o = cube[C7].r;
  cube[C7].r = temp;
  temp = cube[C3].w;
  cube[C3].w = cube[C8].y;
  cube[C8].y = temp;

  temp = cube[C1].w;
  cube[C1].w = cube[C7].y;
  cube[C7].y = temp;
  temp = cube[C3].r;
  cube[C3].r = cube[C8].o;
  cube[C8].o = temp;
}

void g2e(struct aCube * cube) {
  short temp = cube[E20].g;
  cube[E20].g = cube[E17].g;
  cube[E17].g = temp;
  temp = cube[E12].g;
  cube[E12].g = cube[E15].g;
  cube[E15].g = temp;

  temp = cube[E20].o;
  cube[E20].o = cube[E17].r;
  cube[E17].r = temp;
  temp = cube[E12].w;
  cube[E12].w = cube[E15].y;
  cube[E15].y = temp;
}

void g3c(struct aCube * cube) {
  short temp = cube[C1].g;
  cube[C1].g = cube[C3].g;
  cube[C3].g = cube[C7].g;
  cube[C7].g = cube[C8].g;
  cube[C8].g = temp;

  temp = cube[C1].o;
  cube[C1].o = cube[C3].w;
  cube[C3].w = cube[C7].r;
  cube[C7].r = cube[C8].y;
  cube[C8].y = temp;

  temp = cube[C1].w;
  cube[C1].w = cube[C3].r;
  cube[C3].r = cube[C7].y;
  cube[C7].y = cube[C8].o;
  cube[C8].o = temp;
}

void g3e(struct aCube * cube) {
  short temp = cube[E12].g;
  cube[E12].g = cube[E17].g;
  cube[E17].g = cube[E15].g;
  cube[E15].g = cube[E20].g;
  cube[E20].g = temp;

  temp = cube[E12].w;
  cube[E12].w = cube[E17].r;
  cube[E17].r = cube[E15].y;
  cube[E15].y = cube[E20].o;
  cube[E20].o = temp;
}



int rotate( struct aCube * cube, char f, int t) {
  switch (f){

  case 'r':
    switch (t){
    case 1:
      r1c( cube );
      r1e( cube );
      break;
    case 2: 
      r2c( cube );
      r2e( cube );
      break;
    case 3:
      r3c( cube );
      r3e( cube );
      break;
    }
  break;

  case 'w':
    switch (t){
    case 1: 
      w1c( cube );
      w1e( cube );
      break;
    case 2:
      w2c( cube );
      w2e( cube );
      break;
    case 3:
      w3c( cube );
      w3e( cube );
      break;
    }
    break;

  case 'b':
    switch (t){
    case 1: 
      b1c( cube );
      b1e( cube );
      break;
    case 2:
      b2c( cube );
      b2e( cube );
      break;
    case 3:
      b3c( cube );
      b3e( cube );
      break;
    }
    break;

  case 'o':
    switch (t){
    case 1: 
      o1c( cube );
      o1e( cube );
      break;
    case 2:
      o2c( cube );
      o2e( cube );
      break;
    case 3:
      o3c( cube );
      o3e( cube );
      break;
    }
    break;

  case 'y':
    switch (t){
    case 1:
      y1c( cube );
      y1e( cube );
      break;
    case 2:
      y2c( cube );
      y2e( cube );
      break;
    case 3:
      y3c( cube );
      y3e( cube );
      break;
    }
    break;

  case 'g':
    switch (t){
    case 1:
      g1c( cube );
      g1e( cube );
      break;
    case 2:
      g2c( cube );
      g2e( cube );
      break;
    case 3:
      g3c( cube );
      g3e( cube );
      break;
    }
    break;
  }
  return 0;
}


